using System;
using System.Buffers;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using Microsoft.VisualBasic;
using UMC.Data;

namespace UMC.Net
{
    public enum MimeHeadKey
    {
        UnKnown = 0,
        Connection = 1,
        KeepAlive = 2,
        TransferEncoding = 3,
        Host = 4,
        XForwardedHost = 5,
        XRealIP = 6,
        XForwardedFor = 7,
        XForwardedProto = 8,
        Upgrade = 9,
        Cookie = 10,
        ContentLength = 11,
        ETag = 12,
        Origin = 13,
        Referer = 14,
        UserAgent = 15,
        ContentType = 16,
        CacheControl = 17,
        AcceptLanguage = 18,
        Accept = 19,
        AcceptEncoding = 20,
        Pragma = 21,
        Server = 22,
        SetCookie = 23,
        ContentEncoding = 24,
        AccessControlAllowOrigin = 25,
        Location = 26,
        ItmeAccessToken = 27,
        LastModified = 28,
        StrictTransportSecurity = 29,
        ContentDisposition = 30,
        IfNoneMatch = 31,

        AltSvc = 32,
        Link = 33,
        ContentSecurityPolicy = 34,
        ReportTo = 35,
        XForwardedProxy = 36,
        SecFetchDest = 37,
        SecFetchMode = 38,

        SecFetchSite = 39,

        SecCaUa = 40,
        SecCaUaMobile = 41,
        SecCaUaPlatform = 42,
        ContentSecurityPolicyReportOnly = 43,

        IfChallenge = 44,
        // XCacheKey = 45


    }
    public enum HttpMethod
    {
        None = 0,
        CONNECT = 1,
        DELETE = 2,
        GET = 3,
        HEAD = 4,
        // HTTP10 = 5,
        // HTTP11 = 6,
        OPTIONS = 7,
        POST = 8,
        PUT = 9,
        TRACE = 10
    }

    public abstract class Mime : IDataReader, IDisposable
    {
        class Mime2L : Mime
        {
            // bool IsHaveHeader;
            public Mime2L(ByteChunk memory) : base(memory)
            {
                this._headChunk = memory;
            }
            protected override void Body(byte[] buffer, int offset, int size)
            {
                this._headChunk.Temp(buffer.AsSpan(offset, size));
            }
        }
        public static Mime CreateMime(ByteChunk memory)
        {
            return new Mime2L(memory);
        }
        static readonly byte[][] HTTPReqMethods = new byte[10][];
        static Tuple<StringValue, MimeHeadKey>[] tuples = new Tuple<StringValue, MimeHeadKey>[44];
        public static StringValue Method(HttpMethod method)
        {
            return new StringValue(HTTPReqMethods[(int)method - 1]);
        }
        public virtual bool IsOver => this.IsHttpFormatError || this.IsMimeFinish;
        static Mime()
        {

            HTTPReqMethods[0] = System.Text.Encoding.ASCII.GetBytes("GET"); ;
            HTTPReqMethods[1] = System.Text.Encoding.ASCII.GetBytes("OPTIONS");
            HTTPReqMethods[2] = System.Text.Encoding.ASCII.GetBytes("HEAD");
            HTTPReqMethods[3] = System.Text.Encoding.ASCII.GetBytes("POST");
            HTTPReqMethods[4] = System.Text.Encoding.ASCII.GetBytes("PUT");
            HTTPReqMethods[5] = System.Text.Encoding.ASCII.GetBytes("DELETE");
            HTTPReqMethods[6] = System.Text.Encoding.ASCII.GetBytes("TRACE");
            HTTPReqMethods[7] = System.Text.Encoding.ASCII.GetBytes("CONNECT");
            HTTPReqMethods[8] = HTTP11;//System.Text.Encoding.ASCII.GetBytes("HTTP/1.1");
            HTTPReqMethods[9] = HTTP10;//System.Text.Encoding.ASCII.GetBytes("HTTP/1.0");

            Array.Sort(HTTPReqMethods, 0, 10, Comparer<byte[]>.Create((x, y) => x.AsSpan().SequenceCompareTo(y)));


            tuples[0] = Tuple.Create(StringValue.ContentLength, MimeHeadKey.ContentLength);
            tuples[1] = Tuple.Create(StringValue.Connection, MimeHeadKey.Connection);
            tuples[2] = Tuple.Create(StringValue.KeepAlive, MimeHeadKey.KeepAlive);
            tuples[3] = Tuple.Create(StringValue.TransferEncoding, MimeHeadKey.TransferEncoding);
            tuples[4] = Tuple.Create(StringValue.Host, MimeHeadKey.Host);
            tuples[5] = Tuple.Create(StringValue.Upgrade, MimeHeadKey.Upgrade);
            tuples[6] = Tuple.Create(StringValue.Cookie, MimeHeadKey.Cookie);
            tuples[7] = Tuple.Create(StringValue.XForwardedHost, MimeHeadKey.XForwardedHost);
            tuples[8] = Tuple.Create(StringValue.XForwardedFor, MimeHeadKey.XForwardedFor);
            tuples[9] = Tuple.Create(StringValue.XForwardedProto, MimeHeadKey.XForwardedProto);
            tuples[10] = Tuple.Create(StringValue.XRealIP, MimeHeadKey.XRealIP);
            tuples[11] = Tuple.Create(StringValue.ETag, MimeHeadKey.ETag);
            tuples[12] = Tuple.Create(StringValue.Origin, MimeHeadKey.Origin);
            tuples[13] = Tuple.Create(StringValue.Referer, MimeHeadKey.Referer);
            tuples[14] = Tuple.Create(StringValue.UserAgent, MimeHeadKey.UserAgent);
            tuples[15] = Tuple.Create(StringValue.ContentType, MimeHeadKey.ContentType);
            tuples[16] = Tuple.Create(StringValue.CacheControl, MimeHeadKey.CacheControl);
            tuples[17] = Tuple.Create(StringValue.AcceptLanguage, MimeHeadKey.AcceptLanguage);
            tuples[18] = Tuple.Create(StringValue.AcceptEncoding, MimeHeadKey.AcceptEncoding);
            tuples[19] = Tuple.Create(new StringValue("Accept"), MimeHeadKey.Accept);//server
            tuples[20] = Tuple.Create(new StringValue("Pragma"), MimeHeadKey.Pragma);
            tuples[21] = Tuple.Create(new StringValue("Server"), MimeHeadKey.Server);
            tuples[22] = Tuple.Create(StringValue.SetCookie, MimeHeadKey.SetCookie);
            tuples[23] = Tuple.Create(StringValue.ContentEncoding, MimeHeadKey.ContentEncoding);
            tuples[24] = Tuple.Create(StringValue.AccessControlAllowOrigin, MimeHeadKey.AccessControlAllowOrigin);
            tuples[25] = Tuple.Create(StringValue.Location, MimeHeadKey.Location);
            tuples[26] = Tuple.Create(new StringValue("Itme-Access-Token"), MimeHeadKey.ItmeAccessToken);
            tuples[27] = Tuple.Create(StringValue.LastModified, MimeHeadKey.LastModified);
            tuples[28] = Tuple.Create(new StringValue("Strict-Transport-Security"), MimeHeadKey.StrictTransportSecurity);
            tuples[29] = Tuple.Create(new StringValue("Content-Disposition"), MimeHeadKey.ContentDisposition);
            tuples[30] = Tuple.Create(StringValue.IfNoneMatch, MimeHeadKey.IfNoneMatch);
            tuples[31] = Tuple.Create(new StringValue("alt-svc"), MimeHeadKey.AltSvc);
            tuples[32] = Tuple.Create(new StringValue("link"), MimeHeadKey.Link);
            tuples[33] = Tuple.Create(new StringValue("content-security-policy"), MimeHeadKey.ContentSecurityPolicy);
            tuples[34] = Tuple.Create(new StringValue("Report-To"), MimeHeadKey.ReportTo);
            tuples[35] = Tuple.Create(StringValue.XForwardedProxy, MimeHeadKey.XForwardedProxy);
            tuples[36] = Tuple.Create(StringValue.SecFetchDest, MimeHeadKey.SecFetchDest);
            tuples[37] = Tuple.Create(StringValue.SecFetchMode, MimeHeadKey.SecFetchMode);
            tuples[38] = Tuple.Create(StringValue.SecFetchSite, MimeHeadKey.SecFetchSite);
            tuples[39] = Tuple.Create(StringValue.SecCaUa, MimeHeadKey.SecCaUa);
            tuples[40] = Tuple.Create(StringValue.SecCaUaMobile, MimeHeadKey.SecCaUaMobile);
            tuples[41] = Tuple.Create(StringValue.SecCaUaPlatform, MimeHeadKey.SecCaUaPlatform);
            tuples[42] = Tuple.Create(new StringValue("content-security-policy-report-only"), MimeHeadKey.ContentSecurityPolicyReportOnly);
            tuples[43] = Tuple.Create(new StringValue("If-Challenge"), MimeHeadKey.IfChallenge);
            // tuples[44] = Tuple.Create(StringValue.XCacheKey, MimeHeadKey.XCacheKey);

            Array.Sort(tuples, 0, tuples.Length, Comparer<Tuple<StringValue, MimeHeadKey>>.Create((x, y) => x.Item1.Span.IgnoreCaseCompareTo(y.Item1.Span)));//Comparer<Tuple<StringValue, MimeHeadKey>>.Create((x, y) => x.Item1.Span.IgnoreCaseCompareTo(y.Item1.Span)));

        }
        void InitHeadKey(StringValue name)
        {
            this.mimeHeadKey = MimeHeadKey.UnKnown;
            this.HeadKey = name;
            int index = Utility.Search(tuples, 0, tuples.Length, name, (x, y) => x.Item1.Span.IgnoreCaseCompareTo(y.Span));
            if (index > -1)
            {
                this.HeadKey = tuples[index].Item1;
                _headChunk.Scale(name.Length);
                this.mimeHeadKey = tuples[index].Item2;
            }
        }
        public HeadValues Headers
        {
            get
            {
                return _headValues;//.Headers;
            }
        }
        public ByteChunk Memory
        {
            get
            {
                return _headChunk;
            }
        }

        public Mime(ByteChunk memory)
        {
            this._headChunk = memory;
        }
        public static readonly byte[] HTTP11 = System.Text.Encoding.ASCII.GetBytes("HTTP/1.1");
        public static readonly byte[] HTTP10 = System.Text.Encoding.ASCII.GetBytes("HTTP/1.0");
        public static readonly byte[] HeaderEnd = new byte[] { 13, 10, 13, 10 };
        public static readonly byte[] RowEnd = new byte[] { 13, 10 };
        public static readonly byte[] HeaderSplit = new byte[] { 58, 32 };
        public static readonly StringValue RowSplit = new StringValue(RowEnd);
        public static readonly StringValue SplitValue = new StringValue(HeaderSplit);//new byte[] { 58, 32 };

        public HttpMethod Frist
        {
            get;
            private set;
        }
        public StringValue Second
        {
            get;
            set;
        }
        protected StringValue Third
        {
            get;
            private set;
        }

        public StringValue ContentType
        {
            get
            {
                return Headers.Get("Content-Type"u8);
            }
        }
        protected int QueryIndex { get; set; } = -1;
        public bool IsClose { get; private set; }
        public int KeepAlive { get; private set; } = -1;
        public int KeepAliveMax { get; private set; }

        int _ChunkSize = -1;

        void AddHeader(StringValue headKey, MimeHeadKey hk, StringValue headValue)
        {
            var value = headValue.Span;
            switch (hk)
            {
                case MimeHeadKey.Connection:
                    IsClose = Utility.EqualIgnoreCase(value, "Close"u8);
                    break;
                case MimeHeadKey.ContentLength:
                    if (Utility.TryParse(value, 10, out var len))
                    {
                        this.ContentLength = len;
                    }
                    break;
                case MimeHeadKey.KeepAlive:
                    var vd = value.IndexOf("max="u8, true);
                    if (vd >= 0)
                    {
                        if (Utility.TryParse(value.Slice(vd + 4), 10, out var max))
                        {
                            this.KeepAliveMax = max;
                        }
                    }
                    vd = value.IndexOf("timeout="u8, true);
                    if (vd > 0)
                    {
                        if (Utility.TryParse(value.Slice(vd + 8), 10, out var max))
                        {
                            this.KeepAlive = max;
                        }
                    }
                    break;
                case MimeHeadKey.TransferEncoding:
                    if (value.SequenceEqual("chunked"u8))
                    {
                        this.ContentLength = -2;
                    }
                    break;
            }

            if (Header(headKey, hk, headValue))
            {
                _headValues.Add(new HeadValue(headKey, headValue, hk));// { HeadKey = hk });
            }
        }
        protected virtual bool Header(StringValue key, MimeHeadKey headKey, StringValue value)
        {
            return true;
        }

        protected virtual void Headed()
        {

        }

        public virtual void Finish()
        {

        }
        public bool IsReadFrist
        {
            get
            {
                return !isFristRow;
            }
        }

        bool _IsHttpFormatError, _IsMimeFinish;
        public bool IsHttpFormatError
        {
            get
            {
                return _IsHttpFormatError;
            }
            protected set
            {
                _IsHttpFormatError = value;
            }
        }
        public virtual bool IsMimeFinish
        {
            get
            {
                return _IsMimeFinish;
            }

        }
        internal static int UrlDecode(ReadOnlySpan<byte> bytes, Span<byte> decodedBytes)
        {
            int decodedBytesCount = 0;
            int count = bytes.Length;
            for (int i = 0; i < count; i++)
            {
                byte b = bytes[i];

                if (b == '+')
                {
                    b = HeaderSplit[1];// (byte)' ';
                }
                else if (b == '%' && i < count - 2)
                {
                    int h1 = Utility.FromChar(bytes[i + 1]);
                    int h2 = Utility.FromChar(bytes[i + 2]);

                    if ((h1 | h2) != 0xFF)
                    {
                        b = (byte)((h1 << 4) | h2);
                        i += 2;
                    }
                }
                decodedBytes[decodedBytesCount++] = b;
            }
            return decodedBytesCount;
        }
        public virtual bool IsWebSocket => false;
        int _ContentLength = -1;
        public virtual int ContentLength
        {
            get { return _ContentLength; }
            protected set
            {
                if (value == -2)
                {
                    _ChunkSize = 0;
                }
                else if (value > 0)
                {
                    _ChunkSize = _ContentLength = value;
                }
                else
                {
                    _ContentLength = 0;
                }
            }
        }


        public void ReceiveException(Exception ex)
        {
            this.IsHttpFormatError = true;

            this.ReceiveError(ex);
        }
        protected virtual void ReceiveError(Exception ex)
        {

        }
        public int ChunkSize => _ChunkSize;
        protected virtual void Body(byte[] buffer, int offset, int size)
        {

        }
        public bool IsHeaderFinish
        {
            get
            {
                return !isHeader;
            }

        }

        bool isHeader = true;
        bool isChunked = false;
        HeadValues _headValues = new HeadValues();
        protected ByteChunk _headChunk;
        bool isFristRow = true;
        protected bool IsValueStart = false;
        bool _IsKeyStart = false;
        public bool IsKeyStart => _IsKeyStart;
        StringValue HeadKey;
        MimeHeadKey mimeHeadKey;
        bool isEscape = false;

        protected virtual int HeadValue(MimeHeadKey mimeHeadKey, ReadOnlySpan<byte> bytes)
        {
            int index = bytes.IndexOf((byte)13);
            if (index > -1)
            {
                _headChunk.Temp(bytes.Slice(0, index));
                this.AddHeader(HeadKey, mimeHeadKey, _headChunk.Temp());
                this.IsValueStart = false;
                return index + 1;
            }
            else
            {
                _headChunk.Temp(bytes);
                return bytes.Length;
            }
        }
        protected virtual StringValue PathValue(StringValue stringValue)
        {
            return stringValue;

        }
        public virtual int Receive(byte[] buffer, int offset, int size)
        {

            Span<byte> decodedBytes = stackalloc byte[10];
            int nextOffset = offset;
            int end = offset + size;


            while (end > nextOffset)
            {
                if (isHeader)
                {
                    if (isFristRow && Frist == HttpMethod.None)
                    {
                        if (size < 10)
                        {
                            return size;
                        }

                        int startIndex = Utility.FindIndex(buffer, offset, offset + 10, 32);
                        if (startIndex == -1)
                        {
                            this.IsHttpFormatError = true;
                            return 0;
                        }
                        else
                        {
                            switch (buffer[startIndex + 1])
                            {
                                case (byte)'1':
                                case (byte)'2':
                                case (byte)'3':
                                case (byte)'4':
                                case (byte)'5':
                                case (byte)'6':
                                case (byte)'/':
                                case (byte)'h':
                                    // case 47:
                                    // case 48:
                                    // case 49:
                                    // case 50:
                                    // case 51:
                                    // case 52:
                                    // case 53:
                                    // case 54:
                                    break;
                                default:
                                    this.IsHttpFormatError = true;
                                    return 0;
                            }

                            // if ((buffer[startIndex + 1] < 47 || buffer[startIndex + 1] > 54)
                            // {
                            //     this.IsHttpFormatError = true;
                            //     return 0;
                            // }
                            int fIndex = Utility.Search(HTTPReqMethods, 0, HTTPReqMethods.Length, buffer.AsSpan(offset, startIndex - offset));
                            if (fIndex < 0)
                            {
                                this.IsHttpFormatError = true;
                                return 0;
                            }
                            else
                            {
                                Frist = (HttpMethod)(fIndex + 1);
                            }
                            nextOffset = startIndex + 1;
                        }
                    }
                    if (IsValueStart)
                    {
                        nextOffset += this.HeadValue(this.mimeHeadKey, buffer.AsSpan(nextOffset, end - nextOffset));
                        if (end == nextOffset)
                        {
                            return 0;
                        }
                    }
                    var chvalue = buffer[nextOffset];
                    nextOffset++;
                    switch (chvalue)
                    {
                        case 32:
                            if (isFristRow)
                            {
                                if (this.Second == null)
                                {
                                    this.Second = PathValue(_headChunk.Temp());
                                }
                                else
                                {
                                    goto default;
                                }
                            }
                            else
                            {
                                goto default;
                            }

                            break;
                        case 47:
                            if (isFristRow && _headChunk.TempSize >= 3)
                            {
                                var temp = _headChunk.Chunk.AsSpan(_headChunk.Size, _headChunk.TempSize);
                                if (temp.EndsWith("/.."u8))
                                {
                                    this.IsHttpFormatError = true;
                                    return 0;
                                }
                                else if (isEscape)
                                {
                                    int len = UrlDecode(temp.Slice(temp.Length > 9 ? temp.Length - 9 : 0), decodedBytes);
                                    var vs = decodedBytes.Slice(0, len);
                                    if (vs.EndsWith("/.."u8))
                                    {
                                        this.IsHttpFormatError = true;
                                        return 0;
                                    }

                                }
                            }
                            goto default;
                        case 70:
                        case 102:
                            if (isFristRow && isEscape)
                            {
                                var temp = _headChunk.Chunk.AsSpan(_headChunk.Size, _headChunk.TempSize);
                                if (temp.EndsWith("%2"u8))
                                {
                                    if (temp.Length > 11)
                                    {
                                        int len = UrlDecode(temp.Slice(temp.Length - 11, 9), decodedBytes);
                                        var vs = decodedBytes.Slice(0, len);
                                        if (vs.EndsWith("/.."u8))
                                        {
                                            this.IsHttpFormatError = true;
                                            return 0;
                                        }
                                    }
                                    else
                                    {
                                        int len = UrlDecode(temp.Slice(0, temp.Length - 2), decodedBytes);
                                        var vs = decodedBytes.Slice(0, len);
                                        if (vs.EndsWith("/.."u8))
                                        {
                                            this.IsHttpFormatError = true;
                                            return 0;
                                        }

                                    }

                                }
                            }
                            goto default;

                        case 37:
                            if (isFristRow)
                            {
                                isEscape = true;
                            }
                            goto default;
                        // break
                        case 63:
                            if (isFristRow)
                            {
                                if (QueryIndex == -1)
                                    QueryIndex = _headChunk.TempSize;
                            }
                            goto default;
                        case 13:
                            if (isFristRow)
                            {
                                this.Third = _headChunk.Temp();
                            }
                            else if (IsValueStart)
                            {
                                this.AddHeader(HeadKey, mimeHeadKey, _headChunk.Temp());
                                IsValueStart = false;
                            }
                            break;
                        case 58:
                            if (_IsKeyStart)
                            {
                                if (nextOffset == end)
                                {
                                    return 1;
                                }
                                InitHeadKey(_headChunk.Temp());
                                _IsKeyStart = false;
                                if (buffer[nextOffset] == 32)
                                {
                                    nextOffset++;
                                }
                                IsValueStart = true;

                                nextOffset += this.HeadValue(this.mimeHeadKey, buffer.AsSpan(nextOffset, end - nextOffset));

                            }
                            else
                            {
                                goto default;
                            }
                            break;
                        case 10:
                            if (isFristRow)
                            {
                                isFristRow = false;
                                if (Second == null)
                                {
                                    this.IsHttpFormatError = true;
                                    return 0;
                                }
                                _IsKeyStart = true;
                            }
                            else if (_IsKeyStart)
                            {
                                isHeader = false;
                                this.Headed();
                                this.Memory.Temp();
                                if (_ChunkSize == -1 && _ContentLength <= 0)
                                {
                                    _IsMimeFinish = true;
                                    this.Finish();
                                    return end - nextOffset;
                                }
                                var sizeValue = end - nextOffset;
                                return sizeValue > 0 ? this.Receive(buffer, nextOffset, sizeValue) : 0;
                            }
                            else
                            {
                                _IsKeyStart = true;
                            }
                            break;
                        default:
                            _headChunk.Temp(chvalue);
                            break;
                    }
                }
                else if (_ContentLength > 0)
                {
                    var size2 = end - nextOffset;
                    if (size2 >= _ChunkSize)
                    {
                        this.Body(buffer, nextOffset, _ChunkSize);
                        nextOffset += _ChunkSize;
                        _ChunkSize = 0;
                        _IsMimeFinish = true;
                        this.Finish();
                    }
                    else
                    {
                        _ChunkSize -= size2;
                        this.Body(buffer, nextOffset, size2);
                        nextOffset += size2;
                    }
                    return end - nextOffset;
                }
                else
                {
                    while (_ChunkSize >= 0)
                    {
                        if (_ChunkSize > 0)
                        {
                            var size2 = end - nextOffset;

                            if (size2 > _ChunkSize)
                            {
                                this.Body(buffer, nextOffset, _ChunkSize);
                                nextOffset += _ChunkSize;
                                _ChunkSize = 0;
                            }
                            else
                            {

                                this.Body(buffer, nextOffset, size2);
                                _ChunkSize -= size2;
                                return 0;
                            }
                        }


                        var st = UMC.Data.Utility.FindIndex(buffer, nextOffset, end, RowEnd);
                        if (st == nextOffset)
                        {
                            nextOffset = st + 2;
                            if (isChunked)
                            {
                                _IsMimeFinish = true;
                                this.Finish();
                                return end - nextOffset;
                            }
                            else
                            {
                                st = UMC.Data.Utility.FindIndex(buffer, nextOffset, end, RowEnd);
                            }
                        }
                        if (st > -1)
                        {
                            var start = nextOffset;
                            nextOffset = st + 2;
                            if (isChunked)
                            {

                                var sphIndex = UMC.Data.Utility.FindIndex(buffer, start, st, HeaderSplit);
                                if (sphIndex > 0)
                                {
                                    this.AddHeader(_headChunk.Rent(buffer.AsSpan(start, sphIndex - start)), MimeHeadKey.UnKnown, _headChunk.Rent(buffer.AsSpan(sphIndex + 2, st - sphIndex - 2)));
                                }
                                else
                                {

                                    _IsMimeFinish = true;
                                    this.Finish();
                                    return end - nextOffset;
                                }
                            }
                            else
                            {
                                if (UMC.Data.Utility.TryParse(buffer, start, st - start, 16, out _ChunkSize))
                                {
                                    isChunked = _ChunkSize == 0;
                                }
                                else
                                {

                                    IsHttpFormatError = true;

                                    return end - nextOffset;
                                }
                            }
                        }
                        else
                        {

                            return end - nextOffset;
                        }


                    }
                }
            }


            return end - nextOffset;
        }
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                _headChunk.Close();
                _headValues.Dispose();
            }
        }
        public void Dispose()
        {
            Dispose(true);
        }
    }
    public class HeadValue
    {
        public HeadValue(String name, String value)
        {
            this.Name = new StringValue(name.UTF8());
            this.Value = new StringValue(value.UTF8());
        }
        public HeadValue(StringValue name, string value)
        {
            this.Name = name;// new StringValue(name);
            this.Value = new StringValue(value.UTF8());
        }
        public HeadValue(HeadValue hv)//, string value)
        {
            this.Name = hv.Name;// new StringValue(name);
            this.Value = hv.Value;// new StringValue(value.UTF8());
            this.HeadKey = hv.HeadKey;
        }
        internal HeadValue(StringValue name, StringValue value, MimeHeadKey headKey)
        {

            this.Name = name;
            this.Value = value;//new StringValue(value);
            this.HeadKey = headKey;

        }
        public HeadValue(byte[] name, byte[] value)
        {
            this.Name = new StringValue(name);
            this.Value = new StringValue(value);
        }
        public HeadValue(byte[] name, StringValue value)
        {
            this.Name = new StringValue(name);
            this.Value = value;//new StringValue(value);
        }
        public int Length
        {
            get
            {
                return this.Name.Length + this.Value.Length;
            }
        }
        public HeadValue(StringValue name, byte[] value)
        {
            this.Name = name;
            this.Value = new StringValue(value);
        }
        public HeadValue(StringValue name, StringValue value)
        {
            this.Name = name;
            this.Value = value;//new StringValue(value);
        }
        public StringValue Name
        {
            get;
            set;
        }

        public StringValue Value
        {
            get;
            set;
        }
        public MimeHeadKey HeadKey
        {
            get;
            private set;
        }

    }
}
